#include "StdAfx.h"
#include "Area.h"
#include "ObjectManager.h"
#include "Entity.h"
#include "Render.h"
#include "Messages.h"
#include "ResourceManager.h"
#include "gmArea.h"
#include "AreaView.h"

CArea::CArea(CObjectManager* pOM, gmMachine* pGM, CAreaView* pOwner) : m_objects(), m_pOManager(pOM), m_pUser(0), m_pGM(pGM), m_pOwner(pOwner)
{
	//User object creation
	m_pUser = gmArea::CreateAreaObject( pGM, this );
}

CArea::~CArea(void)
{
	//Release user object
	if( m_pUser )
	{
		gmArea::DestroyAreaObject(m_pGM, m_pUser);
	}
}

ObjectID CArea::GetByName( const std::string& name )
{
	//Search through all objects
	ObjectList::iterator iter = m_objects.begin();
	for(; iter != m_objects.end(); iter++)
	{
		//Get the entity component
		CEntity* pEnt = dynamic_cast<CEntity*>(m_pOManager->GetComponent(*iter, CEntity::COMPONENT_ID));

		//Check if they have the same name
		if(pEnt->WorldName() == name)
		{
			return *iter;
		}
	}
	return -1;
}

unsigned int CArea::GetActivePlayerID( void ) { return m_pOwner->GetActivePlayerID(); }

void CArea::SetPlayerArea( unsigned int PlayerID )
{
	m_pOwner->SetPlayerArea(PlayerID, this);
}

bool CArea::CompareDepth( ObjectID first, ObjectID second, CObjectManager* pOManager )
{
	//Get the entity objects
	CEntity *pFirst = dynamic_cast<CEntity*>(pOManager->GetComponent(first, CEntity::COMPONENT_ID)),
		*pSecond = dynamic_cast<CEntity*>(pOManager->GetComponent(second, CEntity::COMPONENT_ID));
	float z1 = pFirst->Position().m_z, z2 = pSecond->Position().m_z;

	//Check for Render component
	try {
		CRender *pRFirst = dynamic_cast<CRender*>(pOManager->GetComponent(first, CRender::COMPONENT_ID));
		z1 += pRFirst->GetImageInformation("height");
	} catch(...) {}
	try {
		CRender *pRSecond = dynamic_cast<CRender*>(pOManager->GetComponent(second, CRender::COMPONENT_ID));
		z2 += pRSecond->GetImageInformation("height");
	} catch(...) {}


	//Compare depths
	return z1 < z2;
}

void CArea::AddObject( const std::string& file, const ParameterList& params )
{
	//Create object
	ObjectID id = m_pOManager->CreateObject(file, params, this);
	if(id == -1) return;

	//Add the object to the list
	m_objects.push_back(id);
}

void CArea::Disown( ObjectID objectID )
{
	//Remove it
	m_objects.remove(objectID);
}

void CArea::Own( ObjectID objectID )
{
	//Add to our list
	m_objects.push_back( objectID );
}

void CArea::Render(void)
{
	//Draw background
	RECT rc = Resource()->GetTextureManager()->GetRect(m_background);
	Resource()->GetSprite()->Draw( m_background, 0, 0, rc.right, rc.bottom );

	//Sort the object array
	m_objects.sort( boost::bind(CompareDepth, _1, _2, m_pOManager) );

	//Render them in order
	ObjectList::iterator iter = m_objects.begin();
	for(; iter != m_objects.end(); iter++)
	{
		m_pOManager->Message(*iter, Messages::Render);
	}
}

void CArea::Update(float fElapsed, float fTotal)
{
	//Run transports
	TransportList::iterator titer = m_transports.begin();
	for(; titer != m_transports.end(); titer++)
	{
		//Change ownership
		Disown(titer->toMove);
		titer->pDest->Own(titer->toMove);

		//Change position
		CEntity* pEnt = reinterpret_cast<CEntity*>(m_pOManager->GetComponent( titer->toMove, CEntity::COMPONENT_ID ));
		pEnt->Position(titer->pos, false);

		//Make the object manager take care of behind the scenes work
		m_pOManager->SetArea(titer->toMove, titer->pDest);

		//Tell the object it happened
		m_pOManager->CallHook(titer->toMove, "AreaChanged");
	}
	m_transports.clear();

	//Update each object
	ObjectList::iterator iter = m_objects.begin();
	for(; iter != m_objects.end(); iter++)
	{
		m_pOManager->Message(*iter, Messages::Update, fElapsed);
	}
}

void CArea::RegisterTransport(ObjectID obj, CArea *pDest, const bug::math::CVector &newPos)
{
	TransportInfo info = { obj, newPos, pDest };
	m_transports.push_back(info);
}

void CArea::SetBackground( const std::string& name )
{
	//Save name
	m_backgroundName = name;


	//Load the background image
	m_background = Resource()->CreateTexture(m_backgroundName);
}

//Loads an area from a file
bool LoadFromFile( const std::string& filename, CArea* pArea )
{
	//Open file for reading
	std::ifstream file(filename.c_str());
	if(file.fail()) return false;

	using namespace std;

	//Read background name
	std::string back;
	getline(file, back);

	//Load image
	pArea->SetBackground( back );

	//Read a line
	string type;
	while(getline(file, type))
	{
		//Read until {
		string waste;
		getline(file, waste, '{');

		//Get body
		string body;
		getline(file, body, '}');
		getline(file, waste);
		std::stringstream strbody = stringstream(body);

		ParameterList params;

		//Read each line
		string line;
		while( getline( strbody, line ) )
		{
			if(line.empty()) continue;

			//Name to the :
			string name = line.substr(0, line.find_first_of(':'));

			//Value to the end
			string value = line.substr(line.find_first_of(':') + 1);

			//Add to parameter
			params[name] = value;
		}

		//Create object
		pArea->AddObject(type, params);
	}
	return true;
}